package com.pkche.core.advanced.util.weixin;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import javax.servlet.http.HttpServletRequest;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class MessageUtil {
	
	private static final Logger logger = Logger.getLogger(MessageUtil.class);
	/** 
     * 返回消息类型：文本 
     */  
    public static final String RESP_MESSAGE_TYPE_TEXT = "text";  
  
    /** 
     * 返回消息类型：音乐 
     */  
    public static final String RESP_MESSAGE_TYPE_MUSIC = "music";  
    
    /** 
     * 返回消息类型：图文 
     */  
    public static final String RESP_MESSAGE_TYPE_IMAGE= "image";  
  
    /** 
     * 返回消息类型：图文 
     */  
    public static final String RESP_MESSAGE_TYPE_NEWS = "news";  
  
    /** 
     * 请求消息类型：文本 
     */  
    public static final String REQ_MESSAGE_TYPE_TEXT = "text";  
  
    /** 
     * 请求消息类型：图片 
     */  
    public static final String REQ_MESSAGE_TYPE_IMAGE = "image";  
  
    /** 
     * 请求消息类型：链接 
     */  
    public static final String REQ_MESSAGE_TYPE_LINK = "link";  
  
    /** 
     * 请求消息类型：地理位置 
     */  
    public static final String REQ_MESSAGE_TYPE_LOCATION = "LOCATION";  
  
    /** 
     * 请求消息类型：音频 
     */  
    public static final String REQ_MESSAGE_TYPE_VOICE = "voice";  
    
    /**
     * 请求消息类型：小视频
     */
    public static final String REQ_MESSAGE_TYPE_SHORTVIDEO = "shortvideo";
    
    /**
     *  请求消息类型：视频
     */
    public static final String REQ_MESSAGE_TYPE_VIDEO = "video";
   
    /** 
     * 请求消息类型：推送 
     */  
    public static final String REQ_MESSAGE_TYPE_EVENT = "event";  
  
    /** 
     * 事件类型：subscribe(订阅) 
     */  
    public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";  
  
    /** 
     * 事件类型：unsubscribe(取消订阅) 
     */  
    public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";  
  
    /** 
     * 事件类型：CLICK(自定义菜单点击事件) 
     */  
    public static final String EVENT_TYPE_CLICK = "CLICK";  
    
    /** 
    * 事件类型：CLICK(链接点击事件) 
    */  
   public static final String EVENT_TYPE_VIEW = "VIEW";  
   
   /**
    * 事件类型: SCAN(二维码扫描事件)
    */
   public static final String EVENT_TYPE_SCAN = "SCAN";
  
    /** 
     * 解析微信发来的请求（XML） 
     *  
     * @param request 
     * @return 
     * @throws Exception 
     */  
    @SuppressWarnings("unchecked")  
    public static Map<String, String> parseXml(HttpServletRequest request) throws Exception{  
        Map<String, String> map = new HashMap<String, String>();  
        InputStream inputStream = request.getInputStream(); 
        String decodeXML = "";
        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
        String line = null;
        StringBuilder sb = new StringBuilder();
        while((line = br.readLine())!=null){
               sb.append(line);
               sb.append("\r\n");
         }
        try{
         decodeXML = URLDecoder.decode(sb.toString(), "UTF-8");
        }catch(Exception e){
        	logger.error("内容中含有百分号之类的导致解码错误", e);
        	decodeXML = sb.toString();
        }
        logger.debug(decodeXML);
        Document document = DocumentHelper.parseText(decodeXML);  
        Element root = document.getRootElement();  
        List<Element> elementList = root.elements();  
        for (Element e : elementList)  
            map.put(e.getName(), e.getText());  
  
        inputStream.close();  
        inputStream = null;  
        return map;  
    }  
  
    /**
     * 解析XML文件
     * @param strxml
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
	public static Map<String, String> parseXml(String strxml) throws Exception {
		if(StringUtils.isBlank(strxml)) {
			return null;
		}
		Map<String, String> map = new HashMap<String, String>();
		String decodeXML = "";
		Map<String, String> m = new HashMap<String, String>();
		InputStream inputStream = new ByteArrayInputStream(strxml.getBytes());
		BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
		/*SAXBuilder builder = new SAXBuilder();
		org.jdom.Document doc = builder.build(in);
		org.jdom.Element root = doc.getRootElement();
		List list = root.getChildren();
		Iterator it = list.iterator();
		while(it.hasNext()) {
			org.jdom.Element e = (org.jdom.Element) it.next();
			String k = e.getName();
			String v = "";
			List children =  e.getChildren();
			if(children.isEmpty()) {
				v = e.getTextNormalize();
			} else {
				v = getChildrenText(children);
			}
			
			m.put(k, v);
		}
		
		//关闭流
		in.close();*/
		
		String line = null;
        StringBuilder sb = new StringBuilder();
        while((line = br.readLine())!=null){
        	sb.append(line);
            sb.append("\r\n");
        }
        try{
        	decodeXML = URLDecoder.decode(sb.toString(), "UTF-8");
        }catch(Exception e){
        	logger.error("内容中含有百分号之类的导致解码错误", e);
        	decodeXML = sb.toString();
        }
        logger.debug(decodeXML);
        Document document = DocumentHelper.parseText(decodeXML);  
        Element root = document.getRootElement();  
        List<Element> elementList = root.elements();  
        for (Element e : elementList)  
            map.put(e.getName(), e.getText());  
  
        inputStream.close();  
        inputStream = null;
		return map;
	}
    
    /**
	 * 获取子结点的xml
	 * @param children
	 * @return String
	 */
	public static String getChildrenText(List children) {
		StringBuffer sb = new StringBuffer();
		if(!children.isEmpty()) {
			Iterator it = children.iterator();
			while(it.hasNext()) {
				org.jdom.Element e = (org.jdom.Element) it.next();
				String name = e.getName();
				String value = e.getTextNormalize();
				List list = e.getChildren();
				sb.append("<" + name + ">");
				if(!list.isEmpty()) {
					sb.append(getChildrenText(list));
				}
				sb.append(value);
				sb.append("</" + name + ">");
			}
		}
		
		return sb.toString();
	}
    
    /** 
     * 文本消息对象转换成xml 
     *  
     * @param textMessage 文本消息对象 
     * @return xml 
     */  
    public static String textMessageToXml(TextMessage textMessage) {  
        xstream.alias("xml", textMessage.getClass());  
        return xstream.toXML(textMessage);  
    }  
    
    /**
     * 图片消息对象转换成xml
     * @param imgMessage
     * @return
     */
    public static String imgMessageToXml(ImageMessage imgMessage){
    	xstream.alias("xml", imgMessage.getClass());
    	xstream.alias("Image", new Media().getClass());
    	return xstream.toXML(imgMessage);
    }
  
    /** 
     * 音乐消息对象转换成xml 
     *  
     * @param musicMessage 音乐消息对象 
     * @return xml 
     */  
    public static String musicMessageToXml(MusicMessage musicMessage) {  
        xstream.alias("xml", musicMessage.getClass());  
        return xstream.toXML(musicMessage);  
    }  
  
    /** 
     * 图文消息对象转换成xml 
     *  
     * @param newsMessage 图文消息对象 
     * @return xml 
     */  
    public static String newsMessageToXml(NewsMessage newsMessage) {  
        xstream.alias("xml", newsMessage.getClass());  
        xstream.alias("item", new Article().getClass());  
        return xstream.toXML(newsMessage);  
    }  
  
    /**
     * 微信支付通用对象转换成xml(仅仅是拼接起来的xml字符串)
     * @param obj
     * @return
     * @throws IllegalAccessException 
     * @throws IllegalArgumentException 
     */
	@SuppressWarnings("rawtypes")
	public static String wxpayMessageToXml(Object obj) {
		StringBuffer sb = new StringBuffer();
		try {
			sb.append("<xml>");
			Class cls = obj.getClass();
			//获取属性数组
			Field[] fields = cls.getDeclaredFields();
			for(Field field : fields) {
				//存入属性描述器
				PropertyDescriptor pd = new PropertyDescriptor(field.getName(), cls);
				//通过get方法获取属性值，set方法为getWriteMethod()
				Method method = pd.getReadMethod();
				Object o = method.invoke(obj);
				
				sb.append("<")
				.append(field.getName())
				.append(">")
				.append(o)
				.append("</")
				.append(field.getName())
				.append(">");
			}
			sb.append("</xml>");
		} catch (Exception ex) {
			ex.printStackTrace();
		}
        return sb.toString();   
    }
	
    /** 
     * 扩展xstream，使其支持CDATA块 
     *  
     * @date 2013-05-19 
     */  
    private static XStream xstream = new XStream(new XppDriver() {  
        public HierarchicalStreamWriter createWriter(Writer out) {  
            return new PrettyPrintWriter(out) {  
                // 对所有xml节点的转换都增加CDATA标记  
                boolean cdata = true;  
  
                @SuppressWarnings("rawtypes")
				public void startNode(String name, Class clazz) {  
                    super.startNode(name, clazz);  
                }  
  
                protected void writeText(QuickWriter writer, String text) {  
                    if (cdata) {
                        writer.write("<![CDATA[");  
                        writer.write(text);  
                        writer.write("]]>");  
                    } else {  
                        writer.write(text);  
                    }  
                }  
            };  
        }  
    });
}
